using System;
using System.Collections;
using System.Data;
using System.Web.UI.WebControls;
using PHSRAG.Insight21.Common.Pages;
using PHSRAG.Insight21.InsightWebControls;
using PHSRAG.Insight21.Policy;
using PHSRAG.Insight21.Reports;
using PHSRAG.Insight21.SearchContext;
using PHSRAG.Utility;
using Constants = PHSRAG.Insight21.InsightUtilities.Constants;
using PurchasingEnums = PHSRAG.Insight21.Purchasing.Enumerations;

namespace PHSRAG.Insight21.Agreements
{
    /// <summary>
    /// Patient Care Details  page is used to display Patient Care Expense details
    /// for a single Agreement. 
    /// </summary>
    public partial class PatientCareDetailsPage : GridPage
    {
        #region Constants

        private static string IncomingFundNumberKey = "IncomingFundNumberKey_CE3ACE4F-5583-4e65-A646-5170B8F97606";

        #endregion

        #region Private Instance Variable

        // Cache Policy variables, Page level and the Middle ware level cache
        private ICachePolicy cachePolicy;
        private ICachePolicy pageCachePolicy;
        private int pageSize;
        private PatientCareDetails patientCareDetails;

        #endregion

        public PatientCareDetailsPage()
            : base(Keys.PatientCareDetailsPageKey)
        {
        }

        #region Private Properties

        /// <summary>
        /// Gets/Sets fund number passed down from other pages that post to this, 
        /// set once on page load, is stored in pagecache to be utilized
        /// across postbacks
        /// </summary>
        /// </summary>
        private string IncomingFundNumber
        {
            get
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.TransactionDetailsPageKey) as Hashtable;
                return (h == null || h[IncomingFundNumberKey] == null) ? string.Empty : h[IncomingFundNumberKey].ToString();
            }
            set
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.TransactionDetailsPageKey) as Hashtable ?? new Hashtable();
                h[IncomingFundNumberKey] = value;
                pageCachePolicy.Cache(Keys.TransactionDetailsPageKey, h);
            }
        }

        private int PageSize
        {
            get
            {
                if (pageSize == 0)
                {
                    pageSize = Settings.GetKeyValue("PatientCareDetailsDataGrid.ItemsPerPage", 20);
                }
                return pageSize;
            }
        }

        private int PageCount
        {
            get
            {
                return (PatientCareDetails.RecordCount/PageSize) +
                    (((PatientCareDetails.RecordCount%PageSize) == 0) ? 0 : 1);
            }
        }

        private PatientCareDetails PatientCareDetails
        {
            get
            {
                SearchCriteria searchCriteria =
                    ((CommonSearchContext) cachePolicy.GetCachedObject(CommonSearchContext.CacheKey)).GetSearchCriteria(Page.Request.Url.ToString());
                if (patientCareDetails.GetDataContainer() == null)
                {
                    patientCareDetails.Load(DataAccess.ConnectionString, searchCriteria, IncomingFundNumber, SortColumn, SortAscending, CurrentPageIndex, PageSize);
                }
                return patientCareDetails;
            }
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Sets the page index to zero, loads the grid and adjusts the active
        /// paging links according to the location in the array of financial summary Ids.
        /// </summary>
        protected void OnFirstPage(object sender, CommandEventArgs e)
        {
            CurrentPageIndex = 1;
            patientCareDetails.Reset();
            LoadDataGrid();
        }

        /// <summary>
        /// Sets the page index to the last page, loads the grid and adjusts
        /// the pager controls navigation links.
        /// </summary>
        protected void OnLastPage(object sender, CommandEventArgs e)
        {
            try
            {
                CurrentPageIndex = pagerAboveDatagrid.PageCount;
                patientCareDetails.Reset();
                LoadDataGrid();
            }
            catch (Exception ex)
            {
                annunciator.Title = "Following error(s) occurred navigating to last page:";
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        /// <summary>
        /// If not on the last page, increments the page index, loads the grid and adjusts
        /// the pager controls navigation links.
        /// </summary>
        protected void OnNextPage(object sender, CommandEventArgs e)
        {
            try
            {
                ++CurrentPageIndex;
                patientCareDetails.Reset();
                LoadDataGrid();
            }
            catch (Exception ex)
            {
                annunciator.Title = "Following error(s) occurred navigating to next page:";
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        /// <summary>
        /// If the current page is greater than 0, decrements the current page index,
        /// loads the data grid and adjusts the pager controls navigation links.
        /// </summary>
        protected void OnPreviousPage(object sender, CommandEventArgs e)
        {
            try
            {
                --CurrentPageIndex;
                patientCareDetails.Reset();
                LoadDataGrid();
            }
            catch (Exception ex)
            {
                annunciator.Title = "Following error(s) occurred navigating to previous page:";
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        protected void OnSort(object source, DataGridSortCommandEventArgs e)
        {
            if (e.SortExpression != string.Empty)
            {
                SortAscending = (SortColumn == e.SortExpression) ? !SortAscending : true;
                SortColumn = e.SortExpression;
                patientCareDetails.Reset();
                CurrentPageIndex = 1;
                LoadDataGrid();
            }
        }

        protected void OnItemCreated(object sender, DataGridItemEventArgs e)
        {
            try
            {
                if (e.Item.ItemType == ListItemType.Header && patientDetailsGrid.Visible)
                {
                    Label sortSymbol = new Label();
                    sortSymbol.CssClass = "Sort";
                    sortSymbol.Text = SortAscending ? Constants.SortAscendingText : Constants.SortDescendingText;
                    sortSymbol.Font.Name = Constants.SortSymbolFontName;

                    foreach (DataGridColumn column in patientDetailsGrid.Columns)
                    {
                        if (column.SortExpression == SortColumn)
                        {
                            (e.Item.Cells[patientDetailsGrid.Columns.IndexOf(column)]).Controls.Add(sortSymbol);
                            break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                annunciator.Title = "Following error(s) occurred during DataGrid item creation:";
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        protected void OnItemDataBound(object sender, DataGridItemEventArgs e)
        {
            try
            {
                DateTime minDate = (projectHeaderBar.Institution == Constants.Institution.MGH) ? new DateTime(2005, 6, 1) : new DateTime(2007, 6, 1);

                if (e.Item.ItemType == ListItemType.Item)
                {
                    DataRow row = ((DataRowView) e.Item.DataItem).Row;
                    if (DateTime.Parse(row[(int) PatientCareDetails.PatientCareDetailColumn.PostDate].ToString()) < minDate)
                    {
                        e.Item.Cells[(int) DataGridColumns.FullChargeAmount].Controls.Clear();
                        e.Item.Cells[(int) DataGridColumns.DiscountAmount].Controls.Clear();
                        e.Item.Cells[(int) DataGridColumns.ExtendedAmount].Controls.Clear();
                    }
                }
                if (e.Item.ItemType == ListItemType.Footer && patientDetailsGrid.Visible)
                {
                    e.Item.Cells[(int) DataGridColumns.FullChargeAmount].Text = PatientCareDetails.AmountSum.ToString("c");
                    e.Item.Cells[(int) DataGridColumns.DiscountAmount].Text = PatientCareDetails.DiscountSum.ToString("c");
                    e.Item.Cells[(int) DataGridColumns.ExtendedAmount].Text = PatientCareDetails.ExtendedSum.ToString("c");
                }
            }
            catch (Exception ex)
            {
                annunciator.Title = "Following error(s) occurred during DataGrid item creation:";
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        #region Page Load

        /// <summary>
        /// </summary>
        /// <param name="sender">Control which rasied the event</param>
        /// <param name="e">Arguments associated with the event</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                downloadBar.SQLReportName = ReportFactory.PatientCareDetails;

                breadCrumb.Add(AgreementDetailsSubNavigation.PatientCareDetailCommand, Settings.GetKeyValue("SubNavigation.AgreementDetails.PatientCareDetailsURL", string.Empty),
                    Settings.GetKeyValue("BreadCrumb.DetailPageLevel", 2));

                patientCareDetails = new PatientCareDetails(cachePolicy);
                if (!IsPostBack)
                {
                    // Call reset here because if the back button was used, we didn't uncache
                    patientCareDetails.Reset();
                    CurrentPageIndex = 1;
                    SortColumn = "ServiceDate";
                    SortAscending = false;

                    Hashtable h = (Hashtable) cachePolicy.GetCachedObject(Constants.AgreementsConstants.AgreementDetailsKey);
                    if (h == null)
                    {
                        throw new Exception("Fund Number for which details to be displayed is not provided");
                    }

                    string incomingFundNumber = h[Keys.FundNumberKey] as string;
                    if (string.IsNullOrEmpty(incomingFundNumber))
                    {
                        throw new Exception("Cannot load transaction deatils without a valid fund number");
                    }
                    IncomingFundNumber = incomingFundNumber;
                    int budgetYear = 0;

                    CommonSearchContext searchContext = cachePolicy.GetCachedObject(CommonSearchContext.CacheKey) as CommonSearchContext;

                    if (h[Keys.BudgetStartDateKey] != null)
                    {
                        searchContext.SetPrimarySearchCriteria(SearchCriteria.Level.Detail,
                            Page.Request.Url.ToString(),
                            Constants.PostFromDateKey,
                            h[Keys.BudgetStartDateKey].ToString(), "Post From Date",
                            CommonSearch.LabelValueSeparator, h[Keys.BudgetStartDateKey].ToString());
                    }

                    if (h[Keys.BudgetEndDateKey] != null)
                    {
                        searchContext.SetPrimarySearchCriteria(SearchCriteria.Level.Detail,
                            Page.Request.Url.ToString(),
                            Constants.PostToDateKey,
                            h[Keys.BudgetEndDateKey].ToString(), "Post To Date",
                            CommonSearch.LabelValueSeparator, h[Keys.BudgetEndDateKey].ToString());
                    }

                    if (h[Keys.POAPEncumbranceKey] != null)
                    {
                        searchContext.SetAdditionalSearchCriteria(Page.Request.Url.ToString(),
                            "daily", h[Keys.POAPEncumbranceKey].ToString());
                    }

                    switch (projectHeaderBar.Institution)
                    {
                        case Constants.Institution.MGH:
                            detailsUnavailable.Text = "Details unavailable before June 1, 2005.";
                            break;
                        case Constants.Institution.BWH:
                            detailsUnavailable.Text = "Details unavailable before June 1, 2007.";
                            break;
                    }

                    //reset the criteria for values that are passed into this page via links so they don't "stick"
                    searchContext.ClearAdditionalSearchCriteria(Constants.FundIDKey);
                    //The following Fundnumber key needs to be reset(otherwise the fundnumber key has the same value added twice in the separated by a Comma) 
                    searchContext.SetAdditionalSearchCriteria(Page.Request.Url.ToString(), Constants.FundNumberKey, IncomingFundNumber);
                    SearchCriteria commonSearchCriteria = searchContext.GetSearchCriteria(Page.Request.Url.ToString());

                    //see if we came from a selected link on the budget overview page
                    object o = pageCachePolicy.GetCachedObject(Keys.SelectedLinkKey);
                    if (o != null)
                    {
                        //a fund was selected on the budget overview page so use that for our IncomingFundNumber
                        string selectedFundNumber = h[Keys.SelectedBudgetDetailFundNumberKey] as string;
                        if (selectedFundNumber != null)
                        {
                            IncomingFundNumber = selectedFundNumber;
                            h.Remove(Keys.SelectedBudgetDetailFundNumberKey);
                        }
                        //assign the budget year to the selected budget year from the budget details page
                        if (h[Keys.SelectedBudgetDetailsYearKey] != null)
                        {
                            budgetYear = (int) h[Keys.SelectedBudgetDetailsYearKey];
                            h.Remove(Keys.SelectedBudgetDetailsYearKey);
                        }
                        cachePolicy.Cache(Constants.AgreementsConstants.AgreementDetailsKey, h);
                    }

                    pageCachePolicy.UnCache(Keys.SelectedLinkKey);
                    searchContext.SetAdditionalSearchCriteria(SearchCriteria.Level.Detail, Page.Request.Url.ToString(), Constants.DetailsKey, "True");

                    if (budgetYear == 0 && h[Keys.BudgetYearKey] != null)
                    {
                        budgetYear = (int) h[Keys.BudgetYearKey];
                    }

                    projectHeaderBar.LoadProjectHeader(IncomingFundNumber, -1, budgetYear);

                    displaySection.Visible = projectHeaderBar.Visible = true;
                    agreementDetailsSubNavigation.SelectedLink = AgreementDetailsSubNavigation.PatientCareDetailCommand;

                    LoadDataGrid();
                }
                else
                {
                    //need to clear additional search criteria previously added except for fundid and details
                    CommonSearchContext searchContext = cachePolicy.GetCachedObject(CommonSearchContext.CacheKey) as CommonSearchContext;
                    searchContext.ClearAdditionalSearchCriteria("fundid", "details");
                    //fix for TrackIt # 7822 - after "clear selections" clicked - the DetailsKey was reset to false: 
                    searchContext.SetAdditionalSearchCriteria(SearchCriteria.Level.Detail, Page.Request.Url.ToString(), Constants.DetailsKey, "True");

                    annunciator.Message = string.Empty;
                    annunciator.Title = string.Empty;
                }
            }
            catch (Exception ex)
            {
                //annunciator.Message = Utility.ExceptionReport.GetExceptionInfo(ex, false);
                DisplayExceptionReport(annunciator, ex);
            }
        }

        #endregion

        #region Search

        /// <summary>
        /// Event handler for the CommonSearch control.
        /// Make sure to set the class name properties on search, this is necessary to set 
        /// to check to see if user has selected Journal Entry order type,
        /// calls private LoadControl method to load information based on search filters,
        /// Collapse the Search Pannel once the information is loaded,
        /// </summary>
        /// <param name="args">Argument associated with the event (contains the search criteria dictionary)</param>
        protected void OnSearch(SearchCriteriaArgs args)
        {
            try
            {
                CommonSearchContext searchContext = cachePolicy.GetCachedObject(CommonSearchContext.CacheKey) as CommonSearchContext;
                SearchCriteria commonSearchCriteria = searchContext.GetSearchCriteria(Page.Request.Url.ToString());
                patientCareDetails.Reset();
                LoadDataGrid();
            }
            catch (Exception ex)
            {
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        /// <summary>
        /// Handler for the event raised by the CommonSearch control when the "Clear Selection" buttion is clicked upon.
        /// The control clears the criretria (specific to this module).
        /// Since in the page life-cycle, the Load occurs before the Clear event, we have to instigate a re-load of the
        /// controls to refelect the fact that the search criteria has been cleared.
        /// </summary>
        /// <param name="sender">Sender of the event</param>
        /// <param name="e">Argument associated with the event</param>
        protected void OnClearSelection(object sender, CommandEventArgs e)
        {
        }

        #endregion

        #region Download Bar Events

        /// <summary>
        /// Invoked by the download bar when it catches an exception.
        /// </summary>
        /// <param name="sender">Control which raised the event</param>
        /// <param name="e">Argument associated with the event</param>
        protected void OnDownloadFailed(object sender, CommandEventArgs e)
        {
            annunciator.Title = "Following error(s) occurred while downloading";
            annunciator.Message = ExceptionReport.GetExceptionInfo((Exception) e.CommandArgument, false);
        }

        #endregion

        #region Header Events

        /// <summary>
        /// Resets the subnavigation selected link before the 
        /// header performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnHeaderNavigate(object sender, CommandEventArgs e)
        {
            PurgeCache();
            agreementsSubNavigation.Reset();
            agreementDetailsSubNavigation.Reset();
        }

        /// <summary>
        /// Purges the cache before the agreements subnavigation header performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnSubNavigate(object sender, CommandEventArgs e)
        {
            PurgeCache();
        }

        /// <summary>
        /// Purges the cache before the agreement details subnavigation header performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnDetailsSubNavigate(object sender, CommandEventArgs e)
        {
            PurgeCache();
        }

        /// <summary>
        /// Purges the cache and sets the correct search context level before the breadcrumb performs a redirect.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void OnNavigate(object sender, CommandEventArgs e)
        {
            if (((CommandEventArgs) (e.CommandArgument)).CommandName == Convert.ToString((int) SearchCriteria.Level.Summary))
            {
                //set the search context's level to the correct level
                CommonSearchContext searchContext = (CommonSearchContext) cachePolicy.GetCachedObject(CommonSearchContext.CacheKey);
                searchContext.CurrentLevel = SearchCriteria.Level.Summary;
            }
            PurgeCache();
        }

        #endregion

        #endregion

        #region Private Methods

        private void LoadDataGrid()
        {
            try
            {
                if (PatientCareDetails.RecordCount > 0)
                {
                    patientDetailsGrid.PageSize = PageSize;
                    patientDetailsGrid.DataSource = PatientCareDetails.GetDataContainer();
                    patientDetailsGrid.DataBind();
                    ManagePagination();
                }
                else
                {
                    patientDetailsGrid.Visible = pagerAboveDatagrid.Visible =
                        pagerBelowDatagrid.Visible = false;
                    annunciator.Message = "No patient care charges found for fund";
                }
            }
            catch (Exception ex)
            {
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        private void ManagePagination()
        {
            pagerAboveDatagrid.RecordCount = pagerBelowDatagrid.RecordCount = PatientCareDetails.RecordCount;
            pagerAboveDatagrid.PageCount = pagerBelowDatagrid.PageCount = PageCount;
            pagerAboveDatagrid.CurrentPage = pagerBelowDatagrid.CurrentPage = CurrentPageIndex;
            int startIndex = (CurrentPageIndex - 1)*PageSize + 1;
            pagerAboveDatagrid.FirstRecord = pagerBelowDatagrid.FirstRecord = startIndex;
            pagerAboveDatagrid.LastRecord = pagerBelowDatagrid.LastRecord = Math.Min(startIndex + PageSize - 1, PatientCareDetails.RecordCount);
        }

        /// <summary>
        /// Uncaches all objects with data for this page.
        /// </summary>
        private void PurgeCache()
        {
            patientCareDetails.Reset();
        }

        #endregion

        #region Web Form Designer generated code

        protected override void OnInit(EventArgs e)
        {
            //
            // CODEGEN: This call is required by the ASP.NET Web Form Designer.
            //
            InitializeComponent();
            base.OnInit(e);
            cachePolicy = (Policy.ICachePolicy) Session[Policy.Names.CachePolicyKey];
            pageCachePolicy = (Policy.ICachePolicy) Session[Policy.Names.PageCachePolicyKey];
        }

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
        }

        #endregion

        #region Nested type: DataGridColumns

        private enum DataGridColumns
        {
            InsitutionalMRN,
            PatientName,
            PatientMRN,
            PostDate,
            ServiceDate,
            ChargeCode,
            CPTCode,
            ChargeDescription,
            Quantity,
            FullChargeAmount,
            DiscountAmount,
            ExtendedAmount
        }

        #endregion
    }
}